/**
 * @Description: 菜单状态管理
 * @Author 卞鹏飞 <228443632@qq.com>
 * @create 23/08/24 3:36 PM
 */
import { shallowReactive } from 'vue'
import { defineStore } from 'pinia'
import {
  arrayToObj,
  def,
  eachTree,
  filterTree,
  isArray,
  merge,
  parseJsonNoError,
  parseURL,
  to,
  treeToList,
  uuid
} from 'sf-utils2'
import useLayoutStore from '@store/use-layout-store'
import { _getPathLists } from 'sf-utils2/lib/_helperTreeBase.js'
import useAppStore from '@store/use-app-store.ts'
import { MENU_TYPE_ENUM } from '@/utils/enums.ts'
// import demoApi from '@/api/modules/demo'
import { ElMessage } from 'element-plus'
import { throwError } from '@shared/utils/error'

// types
import type { TRouter } from '@root/types/router'
import type {
  IAppStateUserInfo,
  IAppStateAppDOMInfo,
  IAppStateAppHeaderInfo,
  IAppStateDepartTree,
  IAppStateMenuData,
  IAppStateMenuDataItem
} from '@root/types/app-store'
import type { ShallowReactive } from 'vue'
import loginApi from '@/api/modules/user-center/login'
import profile from '@root/profile.ts'
import { MENU_MICRO_PATH_ENTRIES } from '@/utils/constants.ts'

const id = 'menu-store'

type TAppState = {
  userInfo: IAppStateUserInfo
  router: TRouter
  token: string
  menuData: IAppStateMenuData
  authMenus: ShallowReactive<IAppStateMenuData>
  authMenuBtnList: ShallowReactive<IAppStateMenuData>
  departTree: IAppStateDepartTree
  appHeaderInfo: IAppStateAppHeaderInfo
  appDOMInfo: IAppStateAppDOMInfo
}

export default defineStore(id, {
  state: () => {
    return {
      /**
       * 菜单所有数据
       * @type {IAppStateMenuData}
       */
      menuData: undefined,

      /**
       * 用户权限菜单信息,只包括菜单信息
       * @type {ShallowReactive<IAppStateMenuData>}
       */
      authMenus: undefined,

      /**
       * 权限List最大，包括按钮+菜单
       * @type {ShallowReactive<IAppStateMenuData>}
       */
      authMenuBtnList: undefined
    } as TAppState
  },

  getters: {
    /**
     * 左侧菜单树
     * @private
     */
    _authMenu() {
      return this.authMenus
    },

    /**
     * 左侧菜单平面
     * @private
     */
    _authMenuList() {
      return treeToList({ tree: this._authMenu, props: { children: 'children' } })
    },

    /**
     * 按钮权限List
     * @private
     */
    _authButtonList(state): any {
      const { authMenuBtnList = [] } = state
      const menuTypes = [MENU_TYPE_ENUM.button]
      return authMenuBtnList
        .filter((v) => menuTypes.includes(v.type))
        .map((v) => {
          if (isArray(v.__pathNodes__)) {
            // 获取最近的menu对象
            v.__menuNode__ = v.__pathNodes__.findLast((o) =>
              [MENU_TYPE_ENUM.client, MENU_TYPE_ENUM.menu, MENU_TYPE_ENUM.dir].includes(String(o.type))
            )
            def(v, '__menuNode__')
            if (v.code && !v.code.includes?.('|')) {
              const menuCode = v.__menuNode__?.path
              v.code = `${menuCode}|${v.code}`
            }
            v.parentMenuName = v.__menuNode__?.name
          }
          return v
        })
    },

    /**
     * 按钮权限List映射对象, ${path}|${permission}
     * @private
     */
    _authButtonListObjByCode() {
      return arrayToObj(this._authButtonList, 'code')
    },

    /**
     * 按钮权限List映射对象, 只包括permissionCode 不会携带当前path
     * @private
     */
    _authButtonListObjByPermissionCode() {
      return Object.entries(this._authButtonListObjByCode).reduce((pre, [key, value]) => {
        // eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars
        const [_, permissionCode] = (key.split('|') || []).filter(Boolean)
        if (permissionCode) pre[permissionCode] = value
        return pre
      }, {})
    },

    /**
     * 以key值为path，value为menuItem的映射 权限菜单
     * @param state
     * @return {{}}
     * @private
     */
    _authMenuObjByPath(state) {
      // 菜单信息
      const menuObj = {}
      eachTree({
        tree: state.menuData,
        props: { children: 'children' } as any,
        callbackItem: (item, index, list, parentObj) => {
          item.path ||= ''
          // path有值 且 是应用、菜单、目录
          if (
            item.path &&
            [MENU_TYPE_ENUM.client, MENU_TYPE_ENUM.menu, MENU_TYPE_ENUM.dir].includes(String(item.menuType))
          ) {
            if (!item.path.startsWith('/')) {
              item.path = '/' + item.path
            }
            item.menuNameParentPath = [parentObj?.menuName, item?.menuName]?.filter(Boolean)?.join('/') // 菜单路径名
            menuObj[item.path] = item
          }
        }
      })
      return menuObj
    }
  },

  actions: {
    /**
     * 获取用户权限菜单
     * @return {Promise<void>}
     * */
    async getUserAuthMenus() {
      // TODO 卞
      const [res, err] = await to(profile.IS_PRO ? loginApi.queryMenuListByToken() : loginApi.queryMenuListByToken())
      if (err || res?.code !== 200) {
        const message = err || res?.message || '获取用户权限失败'
        ElMessage.error(message)
        return throwError(`提示`, message)
      }
      this.menuData = this.compatMenuData(res?.data || [])
      this._handleMenuData()
    },

    /**
     * 菜单兼容处理
     */
    compatMenuData(data = []) {
      return data.reduce((pre, cur) => {
        if (cur.systemCode == 'cf') {
          pre.push(...(cur.children || []))
        } else if (cur?.systemCode == 'zsatc_auth') {
          // 权限
          pre.push(cur)
        }
        return pre
      }, [])
      // return (
      //   data.reduce((pre, cur) => {
      //     // 如果的资管端
      //     if (item.systemCode == 'cf') {
      //       return true
      //     }
      //     return false
      //   }, )
      // )
    },

    /**
     * 处理菜单数据
     */
    _handleMenuData() {
      // console.log('menuData', this.menuData)
      console.time('[权限数据转换需要的时间]')

      /**
       * 对后端返回的icon 做层兼容
       * @param icon
       */
      function compatIcon(icon: string) {
        if (/\.svg$/.test(icon)) {
          // 如果是svg
          return icon.replace('.svg', '') + '-active.svg'
        }
        return ''
      }

      /**
       * 对menu对象进行增强
       * @param item
       * @returns {*}
       */
      const enhanceItem = <T extends IAppStateMenuDataItem>(item: T): T => {
        item.type ||= item.menuType
        item.name ||= item.menuName
        item.code ||= item.permissionCode
        item.visible ??= '0'
        if ([MENU_TYPE_ENUM.client, MENU_TYPE_ENUM.menu, MENU_TYPE_ENUM.dir].includes(String(item.menuType))) {
          /**
           * WARNING: 这里做了兼容
           */
          item.icon = (item.icon || '').trim()
          if (item.icon === 'auth' || item.name == '权限管理') {
            // 兼容权限管理
            item.icon = 'auth.svg'
          }
          item.activeIcon = compatIcon(item.icon)

          if (item.path) {
            item.path ||= ''
            if (!item.path.startsWith('/')) item.path = '/' + item.path
            let pathName = (item.path?.split?.('?')?.at(0) || item.path) as string

            /**
             * WARNING: 这里做了映射
             */
            MENU_MICRO_PATH_ENTRIES.forEach(([$0, $1]) => {
              item.path = item.path.replace($0, $1)
              pathName = pathName.replace($0, $1)
            })

            const matches = pathName.match(/(.*?\/):(\w+)/)
            if (matches?.length) {
              item.exp = new RegExp(`^${matches[1]}`)
              item.__isDynamic = true
            } else {
              item.exp = new RegExp(`^${pathName}$`)
              item.__isDynamic = false
            }
            item.params = merge({}, parseURL(item.path), parseJsonNoError(item.params as string) || {})
          }
        }
        item.index = item.path || uuid()
        return item
      }

      this.authMenus =
        shallowReactive(
          filterTree({
            tree: this.menuData,
            retainChild: false, // 是否保留子孙节点
            props: { children: 'children' } as any, // 属性字段映射
            callbackItem: (item) => {
              if ([MENU_TYPE_ENUM.client, MENU_TYPE_ENUM.menu, MENU_TYPE_ENUM.dir].includes(String(item.menuType))) {
                // item.icon ||= 'icon-icon-yy-caidan-wendang'
                enhanceItem<IAppStateMenuDataItem>(item)
                return true
              }
              return false
            }
          })
        ) || []

      this.authMenus.__hasLoaded__ = true // 已经加载过

      this.authMenuBtnList = shallowReactive(
        treeToList({ tree: this.menuData, props: { children: 'children' }, retainPaths: true }).map((v) =>
          enhanceItem(v)
        )
      )
      // console.log('this.authMenus', this.authMenus, this.authMenuBtnList)
      console.timeEnd('权限数据转换需要的时间')
    },

    /**
     * 获取菜单面包屑list
     * @param {string} menuFullPath 菜单地址
     * @return {{pathNodes: (*|*[]), targetMenu: undefined}}
     */
    getMenuBreadcrumbsInfo(menuFullPath: string = '') {
      // console.log('this.router.currentRoute',this.router)
      const appStore = useAppStore()
      menuFullPath ||= appStore.router.currentRoute.fullPath
      const { targetMenu } = appStore.router.__AUTH_ROUTE_NEXT_TO__(menuFullPath)
      if (targetMenu?.__id__) {
        let authMenuListIdObj
        if (!targetMenu?.__pathNodes__?.length) {
          // 如果没有之前路径
          authMenuListIdObj = arrayToObj(this._authMenuList, '__id__')
          const nodes = _getPathLists(targetMenu.__id__).map((v) => authMenuListIdObj[v]) // 路径节点集合
          def(targetMenu, '__pathNodes__', nodes) // 设置成不可枚举，菜单某个节点经过的路径集合
        }
        if (!targetMenu?.__samePathNodes__?.length) {
          const samePathNodes = this._authMenuList.filter((v) => v.path == targetMenu.path)
          def(targetMenu, '__samePathNodes__', samePathNodes) // 设置成不可枚举，相同的菜单地址集合
        }
      }
      return {
        targetMenu,
        pathNodes: targetMenu?.__pathNodes__ || []
      }
    },

    /**
     * 设置菜单高亮
     * @param {string} menuFullPath 菜单路径
     */
    setMenuActive(menuFullPath: string = '') {
      const appStore = useAppStore()
      menuFullPath ||= appStore.router.currentRoute.fullPath
      const { targetMenu, pathNodes } = this.getMenuBreadcrumbsInfo(menuFullPath)
      const layoutStore = useLayoutStore()
      const isVisibleMenuFn = (menuItem) =>
        menuItem.visible == '0' &&
        [MENU_TYPE_ENUM.client, MENU_TYPE_ENUM.menu, MENU_TYPE_ENUM.dir].includes(String(menuItem.type)) // 判断节点是否是有效
      if (targetMenu?.__id__) {
        // 设置激活的菜单值
        const parentMenuPath = pathNodes.findLast(isVisibleMenuFn) // 找到最近的菜单对象，包括自己
        if (parentMenuPath) {
          // 如果存在
          const activeMenu = targetMenu.__samePathNodes__.find(isVisibleMenuFn)
          layoutStore.menuActive = activeMenu?.path
        }
      } else {
        layoutStore.menuActive = menuFullPath
      }
    }
  }
})
